﻿using System;
using System.Text.RegularExpressions;
using System.Text;
using System.Web;
using System.IO;
using System.Linq;//2011-02-17 IsValidImage里的数组的count方法

namespace Tools
{
    /// <summary>
    /// 数据验证类
    /// </summary>
    public class Validate
    {
		private static Regex _regNumberSign = new Regex("^[+-]?[0-9]+$");
        private static Regex _regDecimalSign = new Regex("^[+-]?[0-9]+[.]?[0-9]+$"); //等价于^[+-]?\d+[.]?\d+$
        //private static Regex _regEmail = new Regex("^[\\w-]+@[\\w-]+\\.(com|net|org|edu|mil|tv|biz|info)$");//w 英文字母或数字的字符串，和 [a-zA-Z0-9] 语法一样 
        private static Regex _regCHZN = new Regex("[\u4e00-\u9fa5]");

        #region 图片格式相关
        //  Defined image headers.
        private static byte[][] _imageHeaders = new byte[][]
        {
            new byte[]{ 0xFF, 0xD8 },                                       //  .jpg, .jpeg, .jpe, .jfif, .jif
            new byte[]{ 0x42, 0x4D},                                        //  .bmp
            new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A },   //  .png
            new byte[]{ 0x47, 0x49, 0x46 }                                  //  .gif
        };

        private static string[] _imageFormats = new string[] { "jpg", "bmp", "png", "gif" };//要和上面的_imageHeaders一一对应
        #endregion

        //from http://mynkow.blogspot.com/2010/04/validate-image.html

        /// <summary>
        /// Validate that the stream is of an image file.
        /// </summary>
        /// <remarks>
        /// IMPORTANT: The calling code is responsible for creating and disposing the image stream.
        /// Supported file types: .JPEG .BMP .GIF .PNG .TIF
        /// </remarks>
        /// <param name="imageStream">The stream of a picture file.</param>
        /// <exception cref="Exception">Throws if the stream is of invalid image.</exception>
        /// <returns></returns>
        public static bool IsValidImage(Stream imageStream)
        {
            if (imageStream.Length > 0)
            {
                byte[] header = new byte[8]; // Change size if needed.
                imageStream.Read(header, 0, header.Length);

                return IsValidImage(header);
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="header"></param>
        /// <returns></returns>
        public static bool IsValidImage(byte[] header)
        {
            string imageFormat;
            return IsValidImage(header, out imageFormat);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="header"></param>
        /// <param name="imageFormat"></param>
        /// <returns></returns>
        public static bool IsValidImage(byte[] header, out string imageFormat)
        {
            imageFormat = "";

            int headerMinSize = 8;//Change size if needed.
            if (header.Length >= headerMinSize)
            {
                int index = -1;//图片格式的索引
                bool found = false;//找到了
                bool hasImageHeader = _imageHeaders.Count(magic =>
                {
                    if (!found) index++;
                    int i = 0;
                    if (magic.Length > header.Length)
                        return false;
                    //return magic.Count(b => { return b == header[i++]; }) == magic.Length;

                    if (magic.Count(b => { return b == header[i++]; }) == magic.Length)
                    {
                        found = true;
                        return true;
                    }

                    return false;
                }) > 0;
                //Console.WriteLine(index);

                if (index != -1)
                    imageFormat = _imageFormats[index];

                return hasImageHeader;
            }

            return false;
        }
		
		/// <summary>
		/// 检查Request查询字符串的键值，是否是数字，最大长度限制
		/// </summary>
		/// <param name="req">Request</param>
		/// <param name="inputKey">Request的键值</param>
		/// <param name="maxLen">最大长度</param>
		/// <returns>返回Request查询字符串</returns>
		public static string FetchInputDigit(HttpRequest req, string inputKey, int maxLen)
		{
			string retVal = string.Empty;
			if(inputKey != null && inputKey != string.Empty)
			{
				retVal = req.QueryString[inputKey];
				if(null == retVal)
					retVal = req.Form[inputKey];
				if(null != retVal)
				{
					retVal = SqlText(retVal, maxLen);
                    if (!IsNumber(retVal))
						retVal = string.Empty;
				}
			}
			if(retVal == null)
				retVal = string.Empty;
			return retVal;
		}

        /// <summary>
        /// 判断对象是否为Int32类型的数字
        /// </summary>
        /// <param name="Expression"></param>
        /// <returns></returns>
        public static bool IsInt32(object Expression)
        {
            if (Expression != null)
            {
                string str = Expression.ToString();
                if (str.Length > 0 && str.Length <= 11 && Regex.IsMatch(str, @"^[-]?[0-9]*[.]?[0-9]*$"))
                {
                    if ((str.Length < 10) || (str.Length == 10 && str[0] == '1') || (str.Length == 11 && str[0] == '-' && str[1] == '1'))
                    {
                        return true;
                    }
                }
            }
            return false;

        }

        /// <summary>
        /// 是否是DOUBLE类型的表达式
        /// </summary>
        /// <param name="Expression"></param>
        /// <returns></returns>
        public static bool IsDouble(object Expression)
        {
            if (Expression != null)
            {
                return Regex.IsMatch(Expression.ToString(), @"^([0-9])[0-9]*(\.\w*)?$");
            }
            return false;
        }
		
		/// <summary>
		/// 是否数字字符串 可带正负号,比如01则返回false
		/// </summary>
		/// <param name="str">输入字符串</param>
		/// <returns></returns>
		public static bool IsNumber(string str)
		{
            //Match m = RegNumberSign.Match(inputData);
            //return m.Success;
            if (string.IsNullOrEmpty(str))
                return false;

            return Regex.IsMatch(str, @"^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$", RegexOptions.Compiled);//modified on 12-07
		}
	
		/// <summary>
		/// 是否是浮点数 可带正负号
		/// </summary>
		/// <param name="str">输入字符串</param>
		/// <returns></returns>
		public static bool IsDecimalSign(string str)
		{
            if (string.IsNullOrEmpty(str))
                return false;

            Match m = _regDecimalSign.Match(str);
			return m.Success;
		}		

		/// <summary>
		/// 检测是否有中文字符
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		public static bool IsHasCHZN(string str)
		{
            if (string.IsNullOrEmpty(str))
                return false;

            Match m = _regCHZN.Match(str);
			return m.Success;
		}	

		/*/// <summary>
		/// 是否是合法的email 2010-07-15取消该方法
		/// </summary>
		/// <param name="inputData">输入字符串</param>
		/// <returns></returns>
		public static bool IsEmail(string inputData)
		{
			Match m = RegEmail.Match(inputData);
			return m.Success;
		}*/

        /// <summary>
        /// 检查字符串的长度，中文一个算俩；如果min=0，则允许为空
        /// </summary>
        /// <param name="str"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static bool CheckStringLength(string str, int min, int max)
        {
            if (string.IsNullOrEmpty(str))
            {
                if (min == 0)
                    return true;
            }

            int l = Encoding.UTF8.GetBytes(str).Length;
            return (l >= min && l <= max);
        }

		/// <summary>
		/// 检查字符串最大长度，返回指定长度的串
		/// </summary>
		/// <param name="sqlInput">输入字符串</param>
		/// <param name="maxLength">最大长度</param>
		/// <returns></returns>			
		public static string SqlText(string sqlInput, int maxLength)
		{			
			if(sqlInput != null && sqlInput != string.Empty)
			{
				sqlInput = sqlInput.Trim();							
				if(sqlInput.Length > maxLength)//按最大长度截取字符串
					sqlInput = sqlInput.Substring(0, maxLength);
			}
			return sqlInput;
		}

        /// <summary>
        /// 检测是否符合email格式
        /// </summary>
        /// <param name="str">要判断的email字符串</param>
        /// <returns>判断结果</returns>
        public static bool IsValidEmail(string str)
        {
            //return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
           
            //return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^[a-z0-9]([a-z0-9]*[-_.]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2,3})?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            
            //修改email正则，兼容 chenjun@ustc.mail.com.cn
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^[a-z0-9]([a-z0-9]*[-_.]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+\.)+([a-z]{2,5})+$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        /// <summary>
        /// 判断一个字符串是否仅仅包含字母或者数据 2010-07-19 增加 by 杜有发
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool JustCharsOrNumbers(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^[A-Za-z0-9]+$", RegexOptions.Compiled);
        }

        /// <summary>
        /// 检测是否是正确的Url
        /// </summary>
        /// <param name="str">要验证的Url</param>
        /// <returns>判断结果</returns>
        public static bool IsURL(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^(http|https)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{1,10}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$", 
                RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        /// <summary>
        /// 是否为时间格式为：14:23:52
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsTime(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^((([0-1]?[0-9])|(2[0-3])):([0-5]?[0-9])(:[0-5]?[0-9])?)$", 
                RegexOptions.Compiled);
        }

        /*/// <summary>
        /// 判断文件流是否为UTF8字符集
        /// </summary>
        /// <param name="sbInputStream">文件流</param>
        /// <returns>判断结果</returns>
        public static bool IsUTF8(FileStream sbInputStream)
        {
            int i;
            byte cOctets;  // octets to go in this UTF-8 encoded character 
            byte chr;
            bool bAllAscii = true;
            long iLen = sbInputStream.Length;

            cOctets = 0;
            for (i = 0; i < iLen; i++)
            {
                chr = (byte)sbInputStream.ReadByte();

                if ((chr & 0x80) != 0) bAllAscii = false;

                if (cOctets == 0)
                {
                    if (chr >= 0x80)
                    {
                        do
                        {
                            chr <<= 1;
                            cOctets++;
                        }
                        while ((chr & 0x80) != 0);

                        cOctets--;
                        if (cOctets == 0) return false;
                    }
                }
                else
                {
                    if ((chr & 0xC0) != 0x80)
                    {
                        return false;
                    }
                    cOctets--;
                }
            }

            if (cOctets > 0)
                return false;

            if (bAllAscii)
                return false;

            return true;
        }*/

        /*/// <summary>
        /// 是否为ip
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsIP(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");

        }*/

        /// <summary>
        /// 是否为IP
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsIPSect(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){2}((2[0-4]\d|25[0-5]|[01]?\d\d?|\*)\.)(2[0-4]\d|25[0-5]|[01]?\d\d?|\*)$"
                , RegexOptions.Compiled);
        }

        /// <summary>
        /// 判断字符串是否是YYYY-MM-DD,YYYY/MM/DD,YYYY.MM.DD 字符串
        /// </summary>
        /// <param name="str">待判断字符串</param>
        /// <returns>判断结果</returns>
        public static bool IsDateString(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\/|-|\.)(?:0?2\1(?:29))$)|(?:(?:1[6-9]|[2-9]\d)?\d{2})(\/|-|\.)(?:(?:(?:0?[13578]|1[02])\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\2(?:0?[1-9]|1\d|2[0-8]))$"
                , RegexOptions.Compiled);
        }

        /// <summary>
        /// 判断输入的字符串是不是以指定的分隔符隔开的数字
        /// </summary>
        /// <param name="strList">要确认的字符串</param>
        /// <param name="StrSeprate">分隔符</param>
        /// <returns></returns>
        public static bool IsNumericListString(string strList, char StrSeprate)
        {
            if (strList == null || strList == "")
                return false;
            string[] arr = strList.Split(new char[] { StrSeprate });
            return IsNumericArray(arr);
        }

        /// <summary>
        /// 判断输入的字符串是不是以逗号隔开的数字
        /// </summary>
        /// <param name="strList">要确认的字符串</param>
        /// <returns></returns>
        public static bool IsNumericListString(string strList)
        {
            if (strList == null || strList == "")
                return false;
            string[] arr = strList.Split(new char[] { ',' });
            return IsNumericArray(arr);
        }

        /// <summary>
        /// 判断给定的字符串数组(strNumber)中的数据是不是都为数值型
        /// </summary>
        /// <param name="strNumber">要确认的字符串数组</param>
        /// <returns>是则返加true 不是则返回 false</returns>
        public static bool IsNumericArray(string[] strNumber)
        {
            if (strNumber == null)
                return false;
            if (strNumber.Length < 1)
                return false;
            foreach (string id in strNumber)
            {
                if (!IsNumber(id))
                    return false;
            }
            return true;
        }

        /// <summary>
        /// 验证是否为正整数
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsInt(string str)
        {
            return !string.IsNullOrEmpty(str) && Regex.IsMatch(str, @"^[0-9]*$", RegexOptions.Compiled);
        }

        /*/// <summary>
        /// 返回指定IP是否在指定的IP数组所限定的范围内, IP数组内的IP地址可以使用*表示该IP段任意, 例如192.168.1.*
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="iparray"></param>
        /// <returns></returns>
        public static bool InIPArray(string ip, string[] iparray)
        {
            string[] userip = StringUtil.SplitString(ip, @".");
            for (int ipIndex = 0; ipIndex < iparray.Length; ipIndex++)
            {
                string[] tmpip = StringUtil.SplitString(iparray[ipIndex], @".");
                int r = 0;
                for (int i = 0; i < tmpip.Length; i++)
                {
                    if (tmpip[i] == "*")
                        return true;

                    if (userip.Length > i)
                    {
                        if (tmpip[i] == userip[i])
                            r++;
                        else
                            break;
                    }
                    else
                        break;

                }
                if (r == 4)
                    return true;
            }
            return false;
        }*/

        /// <summary>
        /// 判断文件名是否为浏览器可以直接显示的图片文件名
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns>是否可以直接显示</returns>
        public static bool IsImgFilename(string filename)
        {
            filename = filename.Trim();
            if (filename.EndsWith(".") || filename.IndexOf(".") == -1)
            {
                return false;
            }
            string extname = filename.Substring(filename.LastIndexOf(".") + 1).ToLower();
            return (extname == "jpg" || extname == "jpeg" || extname == "png" || extname == "bmp" || extname == "gif");
        }

        /// <summary>
        /// 判断是否为合法的时间
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsDateTime(string str)
        {
            if (string.IsNullOrEmpty(str))
                return false;
            return Regex.IsMatch(str, @"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-)) (20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d$", RegexOptions.IgnoreCase | RegexOptions.Compiled)

                || Regex.IsMatch(str, @"^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$", RegexOptions.IgnoreCase | RegexOptions.Compiled)
                ;
        }

        /// <summary>
        /// 判断指定的字符串是否在以指定的字符分隔的字符串里
        /// </summary>
        /// <param name="toCheck">要检查的串</param>
        /// <param name="source">源串</param>
        /// <param name="separatedSign">分隔符,特殊符号要处理</param>
        /// <returns></returns>
        public static bool IsInStringSeparatedBySign(string toCheck, string source, string separatedSign)
        {
            source = separatedSign + source + separatedSign;//前后都加
            /*
            string temp = string.Format(@"{0}{1}{0}",separatedSign,toCheck);
            //Log.AddLog(regexp + "\n\r" + source);
            if (source.IndexOf(temp) != -1)
                return true;
            else
                return false;
            //return Regex.IsMatch(source, regexp);*/
            //处理一下分隔符里的特殊符号，比如.
            string exp = string.Format("({0}{1}{0})+", separatedSign, toCheck);
            return Regex.IsMatch(source, exp);
        }

        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsBlank(string str)
        {
            return (str == null || str.Length == 0);
        }

        /// <summary>
        /// 是否为空格
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsWhitespace(string str)
        {
            return (str == null || str.Trim().Length == 0);
        }
    }
}
